
package com.wobaby.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.wobaby.util.log.Log;
import com.wobaby.util.log.LogPrinter;

// Referenced classes of package com.wobaby.util:
//            RenditionUncheckedException

public class ReflectionSupport {

	public ReflectionSupport() {
	}

	public static String interfacesOf(Object obj) {
		StringBuffer sb = new StringBuffer();
		Class interfaces[] = obj.getClass().getInterfaces();
		for (int n = 0; n < interfaces.length; n++) {
			sb.append(interfaces[n].getName());
			if (n + 1 < interfaces.length)
				sb.append(", ");
		}

		return sb.toString();
	}

	public static boolean hasDefaultConstructor(String className) {
		try {
			Class.forName(className).getConstructor(new Class[0]);
			return true;
		} catch (NoSuchMethodException ex) {
			return false;
		} catch (SecurityException ex) {
			return false;
		} catch (ClassNotFoundException ex) {
			return false;
		}
	}

	public static Object invoke(Object obj, String method, Object args[],
			String argTypes[]) {
		LogPrinter log = Log.getLog("reflect");
		if (log.configuredFor(10))
			log.debug(null, "Calling " + formatMethod(method, argTypes));
		Method methods[];
		// int i;
		try {
			methods = obj.getClass().getMethods();
			// i = 0;

			for (int i = 0; i < methods.length; i++) {
				if (i >= methods.length)
					break;
				if (sameMethod(methods[i], method, argTypes))
					return methods[i].invoke(obj, args);
				i++;
				// goto _L1
			}

			throw new RenditionUncheckedException("Can't find method " + method
					+ " on object " + obj.getClass().getName());
		} catch (InvocationTargetException ie) {
			throw new RenditionUncheckedException("Can't invoke method "
					+ method + " on object " + obj.getClass().getName(), ie);
		} catch (IllegalAccessException ex) {
			throw new RenditionUncheckedException("Can't invoke method "
					+ method + " on object " + obj.getClass().getName(), ex);
		}

	}

	public static Object invoke(Object obj, Method method, Object args[]) {
		try {
			return method.invoke(obj, args);
		} catch (InvocationTargetException ite) {
			throw new RenditionUncheckedException("Can't invoke method "
					+ method.getName() + " on object "
					+ obj.getClass().getName(), ite);
		} catch (IllegalAccessException iae) {
			throw new RenditionUncheckedException("Can't invoke method "
					+ method.getName() + " on object "
					+ obj.getClass().getName(), iae);
		}
	}

	public static Object instantiateObject(String name) {
		String errorMessage = "Can't instantiate object of type " + name + ".";
		try {
			Class c = Class.forName(name);
			Constructor constructor = c.getConstructor(new Class[0]);
			return constructor.newInstance(null);
		} catch (ClassNotFoundException cnfe) {
			throw new RenditionUncheckedException(errorMessage, cnfe);
		} catch (NoSuchMethodException nsme) {
			throw new RenditionUncheckedException(errorMessage, nsme);
		} catch (InstantiationException ie) {
			throw new RenditionUncheckedException(errorMessage, ie);
		} catch (IllegalAccessException iae) {
			throw new RenditionUncheckedException(errorMessage, iae);
		} catch (InvocationTargetException ite) {
			throw new RenditionUncheckedException(errorMessage, ite);
		}
	}

	public static Object tryToInstantiateObject(String name) {
		Object returnValue = null;
		try {
			Class c = Class.forName(name);
			Constructor constructor = c.getConstructor(new Class[0]);
			returnValue = constructor.newInstance(null);
		} catch (ClassNotFoundException cnfe) {
		} catch (NoSuchMethodException nsme) {
		} catch (InstantiationException ie) {
		} catch (IllegalAccessException iae) {
		} catch (InvocationTargetException ite) {
		}
		return returnValue;
	}

	public static Method getGetterMethod(Class c, String fieldName) {
		String methodName = "get" + fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1);
		Method returnValue = null;
		try {
			returnValue = c.getMethod(methodName, new Class[0]);
		} catch (NoSuchMethodException nsme) {
			if (fieldName.length() >= 2
					&& fieldName.substring(0, 2).equals("m_")) {
				fieldName = fieldName.substring(2);
				returnValue = getGetterMethod(c, fieldName);
			}
		} catch (SecurityException se) {
		}
		return returnValue;
	}

	public static Method getSetterMethod(Class c, String fieldName,
			Class fieldType) {
		String methodName = "set" + fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1);
		Method returnValue = null;
		try {
			returnValue = c.getMethod(methodName, new Class[] { fieldType });
		} catch (NoSuchMethodException nsme) {
		} catch (SecurityException se) {
		}
		return returnValue;
	}

	public static Object getFieldValue(Object o, String fieldname) {
		Object returnValue = null;
		Method getterMethod = getGetterMethod(o.getClass(), fieldname);
		if (getterMethod != null)
			returnValue = invoke(o, getterMethod, null);
		return returnValue;
	}

	private static boolean sameMethod(Method method, String methodName,
			String argTypes[]) {
		if (!method.getName().equals(methodName))
			return false;
		Class argClasses[] = method.getParameterTypes();
		if (argClasses.length != argTypes.length)
			return false;
		for (int n = 0; n < argClasses.length; n++)
			if (!argClasses[n].getName().equals(argTypes[n]))
				return false;

		return true;
	}

	private static String formatMethod(String methodName, Class classes[]) {
		String classNames[] = new String[classes.length];
		for (int n = 0; n < classes.length; n++)
			classNames[n] = classes[n].getName();

		return formatMethod(methodName, classNames);
	}

	private static String formatMethod(String methodName, String classNames[]) {
		StringBuffer sb = new StringBuffer();
		sb.append(methodName);
		sb.append("(");
		for (int n = 0; n < classNames.length; n++) {
			sb.append(classNames[n]);
			if (n + 1 < classNames.length)
				sb.append(",");
		}

		sb.append(")");
		return sb.toString();
	}
}